package cn.agiledata.bank.linkbank.impl.icbc;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Map;

import cn.com.infosec.icbc.ReturnValue;

import cn.agiledata.bank.common.util.IOUtil;
import cn.agiledata.bank.linkbank.exception.LinkBankException;

/**
 * 中国工商银行网上银行通用类
 * 
 * @author maxianbo
 * 
 */
class IcbcNetPayUtils {
    private IcbcNetPayUtils() {
    }

    /**
     * 按照工商银行生成支付请求数字签名的规则拼凑加密内容
     * 
     * @param values
     *            所有参数
     * @param keys
     *            参与校验的顺序相关的关键字组
     * @param b2b
     *            是否B2B支付
     * @return 拼凑好的加密内容
     */
    private static String getRequestScrabbleContent(Map values, String[] keys,
            boolean b2b) {
        String content = "";
        if (b2b) {
            for (int i = 0; i < keys.length; i++) {
                content += keys[i] + "=" + values.get(keys[i]) + "&";
            }
            if (content.length() > 0) {
                content = content.substring(0, content.length() - 1);
            }
        } else {
            for (int i = 0; i < keys.length; i++) {
                content += values.get(keys[i]);
            }
        }
        return content;
    }

    /**
     * 按照工商银行生成支付响应数字签名的规则拼凑加密内容
     * 
     * @param values
     *            所有参数
     * @param keys
     *            参与校验的顺序相关的关键字组
     * @return 拼凑好的加密内容
     */
    private static String getResponseScrabbleContent(Map values, String[] keys) {
        String content = "";
        for (int i = 0; i < keys.length; i++) {
            content += keys[i] + "=" + values.get(keys[i]) + "&";
        }
        if (content.length() > 0) {
            content = content.substring(0, content.length() - 1);
        }
        return content;
    }

    /**
     * 获取证书文件内容
     * 
     * @param certFilePath
     *            证书文件路径
     * @return 证书文件内容
     * @throws IOException
     */
    private static byte[] getCertContent(String certFilePath)
            throws IOException {
        certFilePath = IOUtil.getAbsolutePath(certFilePath);
        FileInputStream in = new FileInputStream(certFilePath);
        byte[] certContent = new byte[in.available()];
        in.read(certContent);
        in.close();
        return certContent;
    }

    /**
     * 获取证书公钥编码
     * 
     * @param publicKeyFilePath
     *            公钥证书文件相对路径
     * @return 证书公钥编码
     * @throws LinkBankException
     */
    public static String getPublicKeyCode(String publicKeyFilePath)
            throws LinkBankException {
        try {
            byte[] publicKey = getCertContent(publicKeyFilePath);
            byte[] encodeKey = ReturnValue.base64enc(publicKey);
            return new String(encodeKey);
        } catch (Exception e) {
            throw LinkBankException.CANNOT_LOAD_CERT;
        }
    }

    /**
     * 按照工商银行支付请求数字签名的规则生成数字签名
     * 
     * @param values
     *            所有参数
     * @param keys
     *            参与校验的顺序相关的关键字组
     * @param cryptoKey
     *            密钥
     * @param privateKeyFilePath
     *            私钥证书文件相对路径
     * @param b2b
     *            是否B2B支付
     * @return 数字签名
     * @throws LinkBankException
     */
    public static String getDigitalSign(Map values, String[] keys,
            String cryptoKey, String privateKeyFilePath, boolean b2b)
            throws LinkBankException {
        try {
            byte[] content = getRequestScrabbleContent(values, keys, b2b)
                    .getBytes();
            byte[] privateKey = getCertContent(privateKeyFilePath);
            char[] creytoKeyChars = cryptoKey.toCharArray();
            byte[] sign = ReturnValue.sign(content, content.length, privateKey,
                    creytoKeyChars);
            byte[] encodeSign = ReturnValue.base64enc(sign);
            return new String(encodeSign);
        } catch (Exception e) {
            throw LinkBankException.CANNOT_LOAD_CERT;
        }
    }

    /**
     * 按照工商银行支付响应数字签名的规则校验数字签名
     * 
     * @param values
     *            所有参数
     * @param keys
     *            参与校验的顺序相关的关键字组
     * @param digitalSign
     *            待校验的数字签名
     * @param publicKeyFilePath
     *            工商银行公钥证书文件相对路径
     * @return
     * @throws LinkBankException
     */
    public static boolean validateDigitalSign(Map values, String[] keys,
            String digitalSign, String publicKeyFilePath)
            throws LinkBankException {
        try {
            byte[] content = getResponseScrabbleContent(values, keys)
                    .getBytes();
            byte[] publicKey = getCertContent(publicKeyFilePath);
            byte[] decodeSign = ReturnValue.base64dec(digitalSign.getBytes());
            return ReturnValue.verifySign(content, content.length, publicKey,
                    decodeSign) == 0;
        } catch (Exception e) {
            throw LinkBankException.CANNOT_LOAD_CERT;
        }
    }
}
